#ifndef __TIMER_H__
#define __TIMER_H__

#include <cstdint>
#include <memory>
#include <vector>
#include <set>
#include <shared_mutex>
#include <mutex>
#include <thread>
#include <functional>

class TimerManager;

//定时任务类
class Timer: public std::enable_shared_from_this<Timer>
{
    friend class TimerManager;
public:
    using ptr = std::shared_ptr<Timer>;

    //取消定时器
    bool cancel();

    //更新定时器执行时间
    bool refresh();

    //重置定时器
    //ms 定时器执行时间间隔（毫秒）
    //from_now 是否从当前时间开始从新计算m_next
    bool resetTimer(uint64_t ms, bool from_now);

private:
    //构造函数私有， 只能通过TimerManager构造Timer
    //recurring: 是否循环
    //ms: 定时器执行时间间隔
    //manager: 定时器管理器
    //cb: 回调函数
    Timer(bool recurring, uint64_t ms, TimerManager* manager, std::function<void()> cb);

    //next 执行定时任务的时间戳（毫秒）
    Timer(uint64_t next);

    //定时器比较仿函数
    struct Comparator
    {   
        //set容器需要一个小于号的比较器 按照定任务的执行时间比较
        bool operator()(const Timer::ptr& lhs, const Timer::ptr& rhs) const;
    };

private:
    bool m_recurring    = true; //是否为循环定任务
    uint64_t m_ms       = 0;    //执行周期
    uint64_t m_next     = 0;    //精确的执行时间
    TimerManager* m_manager = nullptr;  //定任务管理器
    std::function<void()> m_cb;   ////回调函数
};


//定时任务管理器
class TimerManager
{
    friend class Timer;
public:
    TimerManager();
    virtual ~TimerManager();

    //添加定任务
    //ms 定任务执行的时间间隔
    //cb 定任务回调函数
    //recurring 是否循环定任务
    Timer::ptr addTimer(uint64_t ms, std::function<void()> cb, bool recurring = false);
    
    //添加条件定任务
    //ms 定任务执行的时间间隔
    //cb 定任务回调函数
    //weak_cond 条件
    //recurring 是否循环定任务
    Timer::ptr addConditionTimer(uint64_t ms, std::function<void()> cb,  std::weak_ptr<void> weak_cond, bool recurring = false);

    //返回到最近一个定任务执行的时间间隔（毫秒）
    uint64_t getNextTimer();

    //获取所有超时的定时任务
    //cbs 回调函数数组
    void listExpiredCb(std::vector<std::function<void()>>& cbs);

    //当前是否有定时任务
    bool hasTimer();

protected:
    //当有新的定任务插入到定队列的首部，执行该函数
    virtual void onTimerInsertedAtFront() = 0;

private:
    //将定时器添加到管理器中 判断是否插到了定时器的首部
    void addTimerToSet(Timer::ptr val, std::unique_lock<std::shared_mutex>& write_lock);

    //检测服务器时间是否被调后了
    // bool detectClockRollover(uint64_t now_ms)

private:
    bool    m_tickled = false;  //是否触发onTimerInsertedAtFront - 判断新加入的定时任务是否为容器第一个任务
    std::shared_mutex m_sharedMutex;
    std::set<Timer::ptr, Timer::Comparator> m_timers;  //定时任务容器
};

#endif